package model.schedule;

import java.util.Iterator;
import java.util.Observable;
import java.util.Observer;

import model.database.CalendarWrapper;


public class ScheduleExecuter extends Observable implements Observer {

	private Scheduler scheduler;

	private ScheduleExecuterThread set;

	public ScheduleExecuter(Scheduler scheduler) {
		this.scheduler = scheduler;
		this.scheduler.addObserver(this);
	}

	public void update(Observable o, Object arg1) {
		this.scheduler = (Scheduler) o;
		if (arg1 instanceof Schedule) {
			Schedule schedule = (Schedule) arg1;
			// Exit any current executer
			if (set != null)
				set.exit();

			// Start a new executer
			set = new ScheduleExecuterThread(schedule);
			set.start();
		}
	}

	private class ScheduleExecuterThread extends Thread {

		private Schedule schedule;

		private boolean exitThread;

		public ScheduleExecuterThread(Schedule schedule) {
			this.schedule = schedule;
		}

		public synchronized void exit() {
			// The thread may allready have finished normally
			if (!this.exitThread) {
				this.exitThread = true;
				this.interrupt();
			}
		}

		public void run() {
			Iterator<Ad> itr = schedule.iterator();
			CalendarWrapper timeNow = null;
			while (itr.hasNext()) {
				Ad ad = itr.next();

				// Sleep until the next auction has come to an end
				timeNow = new CalendarWrapper();
				long timeDiff = ad.getEnd().timeMillis()
						- timeNow.timeMillis();
				if (timeDiff > 0) {
					setChanged();
					notifyObservers("Sleeping " + timeDiff + "ms until "+ad.getEnd());
					try {
						Thread.sleep(timeDiff);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				if (this.exitThread)
					return;

				handleAuction(ad);
			}

			this.exitThread = true;
		}

		private void handleAuction(Ad ad) {
			setChanged();
			notifyObservers("Handling ad " + ad.getId());
			AdHandler ah = new AdHandler(ad);
			ah.start();
		}
	}
}
